package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.ServiceException;
import com.zzyl.common.utils.uuid.UUID;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DeviceShadowDataVo;
import com.zzyl.nursing.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * iot设备管理Service业务层处理
 *
 * @author laoYe
 * @date 2025-10-28
 */
@Slf4j
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {

    @Autowired
    private IoTDAClient iotDAClient;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    DeviceMapper deviceMapper;

    /**
     * 新增iot设备管理
     *
     * @param dto iot设备管理
     * @return 结果
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void insertDevice(DeviceDto dto) {
        log.info("添加的数据{}", dto);
        //1.设备名是否重复
        Long count = lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).count();
        if (count > 0) {
            throw new ServiceException("设备名已存在");
        }
        //2.设备标识是否重复
        count = lambdaQuery().eq(Device::getNodeId, dto.getNodeId()).count();
        if (count > 0) {
            throw new ServiceException("设备标识已存在");
        }
        //3.同一位置
        System.out.println("dto = " + dto);
        count = lambdaQuery()
                .eq(Device::getProductKey, dto.getProductKey())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                .eq(Device::getBindingLocation, dto.getBindingLocation()).count();
        System.out.println("同一位置已存在相同的设备count = " + count);
        if (count > 0) {
            throw new ServiceException("同一位置已存在相同的设备");
        }
        String IotId = dto.getProductKey() + "_" + dto.getNodeId();
        dto.setIotId(IotId);
        //生成密钥
        String secrect = UUID.randomUUID().toString().replaceAll("-", "");

        //数据对象
        Device device = BeanUtil.toBean(dto, Device.class);
        //默认无门禁
        device.setHaveEntranceGuard(0);
        device.setSecret(secrect);

        log.info("保存的数据{}", device);
        //5.先保存到数据库
        save(device);
        //6.再注册到iot平台
        registerDevice(dto, secrect);
    }

    /*注册到华为云*/
    private void registerDevice(DeviceDto dto, String secrect) {
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.withProductId(dto.getProductKey());
        body.withDeviceName(dto.getDeviceName());
        body.withNodeId(dto.getNodeId());
        //上面的设备id
        body.withDeviceId(dto.getIotId());
        request.withBody(body);
        AuthInfo authInfo = new AuthInfo();
        //设备的密钥
        authInfo.withSecret(secrect);
        body.setAuthInfo(authInfo);
        request.withBody(body);
        try {
            AddDeviceResponse response = iotDAClient.addDevice(request);
            System.out.println(response.toString());
        } catch (Exception e) {
            throw new ServiceException("物联网接口：设备注册失败");
        }
    }

    /*把产品列表同步到redis中*/
    @Override
    public void syncProductList() {
        ListProductsRequest request = new ListProductsRequest();
        //设置条数
        request.setLimit(50);
        ListProductsResponse response = iotDAClient.listProducts(request);
        if (response.getHttpStatusCode() != 200) {
            throw new ServiceException("物联网接口：查询产品同步失败");
        }
        List<ProductSummary> products = response.getProducts();
        //如果有产品数据才存入redis
        if (CollUtil.isNotEmpty(products)) {
            redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(products));
        }
    }

    /*从redis中取产品列表*/
    @Override
    public List<ProductVo> getAllProduct() {
        //1.从redis中查询,把里面的JSON转成字符串
        String products = (String) redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //2.转成ProductVo再返回
        if (StrUtil.isNotEmpty(products)) {
            return JSONUtil.toList(products, ProductVo.class);
        }
        //防止返回空对象
        return List.of();
    }

    /**
     * 查询iot设备管理列表
     *
     * @param device iot设备管理
     * @return iot设备管理
     */

    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 查询iot设备管理
     *
     * @param iotId iot设备
     * @return iot设备管理
     */
    @Override
    public DeviceDetailVo selectDeviceByIotId(String iotId) {
        //1.首先拿数据库中的内容
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (ObjectUtil.isEmpty(device)) {
            throw new ServiceException("设备不存在");
        }
        //2.根据数据库中的内容拿华为云的
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.setDeviceId(iotId);
        ShowDeviceResponse response;
        try {
            response = iotDAClient.showDevice(request);
        } catch (Exception e) {
            log.info("物联网接口：查询设备详情，调用失败");
            throw new ServiceException("物联网接口：查询设备详情，调用失败");
        }
        //属性拷贝
        DeviceDetailVo vo = BeanUtil.toBean(device, DeviceDetailVo.class);
        vo.setDeviceStatus(response.getStatus());
        //字符转换成日期时间格式
        String activeTimeStr = response.getActiveTime();
        if (StrUtil.isNotEmpty(activeTimeStr)) {
            //解析UTC时间字符串为LocalDateTime
            LocalDateTime activeTime = LocalDateTimeUtil.parse(activeTimeStr, DatePattern.UTC_MS_PATTERN);
            //时区转换，将UTC时间转换为上海时区时间
            activeTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            vo.setActiveTime(activeTime);
        }
        return vo;
    }

    /**
     * 获取设备上报的数据
     *
     * @param iotId 设备ID
     * @return 设备上报的数据
     */
    @Override
    public List<DeviceShadowDataVo> getDeviceShadowData(String iotId) {
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        //调华为接口
        request.setDeviceId(iotId);
        ShowDeviceShadowResponse response = iotDAClient.showDeviceShadow(request);
        if (response.getHttpStatusCode() != 200) {
            throw new ServiceException("物联网接口：查询设备影子数据失败");
        }
        List<DeviceShadowData> shadow = response.getShadow();
        if (CollUtil.isEmpty(shadow)) {
            return Collections.emptyList();
        }
        JSONObject jsonObject = JSONUtil.parseObj(shadow.get(0).getReported().getProperties());
        List<DeviceShadowDataVo> list = new ArrayList<>();
        //
        String eventTimeStr = shadow.get(0).getReported().getEventTime();

        //处理上报时间
        LocalDateTime activeTime = LocalDateTimeUtil.parse(eventTimeStr, "yyyyMMdd'T'HHmmss'Z'");
        //日期时区转换
        LocalDateTime eventTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();
        jsonObject.forEach((key, value) -> {
            DeviceShadowDataVo vo = new DeviceShadowDataVo();
            vo.setFunctionId(key);
            vo.setEventTime(eventTime);
            vo.setValue(value.toString());
            list.add(vo);
        });
        return list;
    }

    /**
     * 修改iot设备管理
     *
     * @param device iot设备管理
     * @return
     */
    @Override
    public void updateDevice(Device device) {
        //1.先修改数据库中的内容
        //1。1通过设备主键id修改设备名称，位置类型，绑定位置
        //2.再修改华为云的内容
        /* UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId("{device_id}");*/
        boolean update = lambdaUpdate().eq(Device::getId, device.getId())
                .set(StrUtil.isNotEmpty(device.getDeviceName()), Device::getDeviceName, device.getDeviceName())
                .set(StrUtil.isNotEmpty(device.getDeviceName()), Device::getLocationType, device.getLocationType())
                .set(StrUtil.isNotEmpty(device.getDeviceName()), Device::getBindingLocation, device.getBindingLocation())
                .set(device.getLocationType() == 0, Device::getPhysicalLocationType, -1)
                .set(device.getLocationType() == 1, Device::getPhysicalLocationType, device.getPhysicalLocationType())
                .set(StrUtil.isNotEmpty(device.getRemark()), Device::getRemark, device.getRemark())
                .set(StrUtil.isNotEmpty(device.getDeviceDescription()), Device::getDeviceDescription, device.getDeviceDescription())
                .update();
        if (!update) {
            throw new ServiceException("修改设备失败");
        }
        //从数据库里查刚刚修改的内容
        Device deviceUpdated = lambdaQuery().eq(Device::getId, device.getId()).one();
        //2.数据库成功再修改华为云的内容
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId(deviceUpdated.getIotId());
        UpdateDevice body = new UpdateDevice();
        body.withDeviceName(deviceUpdated.getDeviceName());
        request.withBody(body);
        try {
            UpdateDeviceResponse response = iotDAClient.updateDevice(request);
        } catch (Exception e) {
            log.error("物联网接口：修改设备失败");
            throw new ServiceException("物联网接口：修改设备失败");
        }
    }
}